
#include <avr/io.h>
#include <util/delay.h>
#include <stdarg.h>
#include <stdio.h>

#include "nibo/display.h"
#include "nibo/delay.h"
#include "nibo/iodefs.h"

#include "nibo/display.h"

// The font is 8 pixels high and 5 pixels wide.
// The first byte of each symbol is the proportional mask. The columns are
// encoded in the following 5 bytes.

const uint8_t fontTiles[]=
{
  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, // <space>
  0x04, 0x00, 0x00, 0x5f, 0x00, 0x00, // !
  0x0e, 0x00, 0x07, 0x00, 0x07, 0x00, // "
  0x1f, 0x14, 0x7f, 0x14, 0x7f, 0x14, // #
  0x1f, 0x24, 0x2a, 0x7f, 0x2a, 0x12, // $
  0x1f, 0x23, 0x13, 0x08, 0x64, 0x62, // %
  0x1f, 0x36, 0x49, 0x55, 0x22, 0x50, // &
  0x06, 0x00, 0x05, 0x03, 0x00, 0x00, // '
  0x0e, 0x00, 0x1c, 0x22, 0x41, 0x00, // (
  0x0e, 0x00, 0x41, 0x22, 0x1c, 0x00, // )
  0x1f, 0x14, 0x08, 0x3e, 0x08, 0x14, // *
  0x1f, 0x08, 0x08, 0x3e, 0x08, 0x08, // +
  0x06, 0x00, 0xa0, 0x60, 0x00, 0x00, // ,
  0x0f, 0x08, 0x08, 0x08, 0x08, 0x08, // -
  0x06, 0x00, 0x60, 0x60, 0x00, 0x00, // .
  0x0e, 0x00, 0x60, 0x1c, 0x03, 0x00, // /
  
  0x1f, 0x3e, 0x51, 0x49, 0x45, 0x3e, // 0
  0x0e, 0x00, 0x42, 0x7f, 0x40, 0x00, // 1
  0x1f, 0x42, 0x61, 0x51, 0x49, 0x46, // 2
  0x1d, 0x21, 0x41, 0x45, 0x4b, 0x31, // 3
  0x1f, 0x18, 0x14, 0x12, 0x7f, 0x10, // 4
  0x1d, 0x27, 0x45, 0x45, 0x45, 0x39, // 5
  0x17, 0x3c, 0x4a, 0x49, 0x49, 0x30, // 6
  0x1e, 0x01, 0x71, 0x09, 0x05, 0x03, // 7
  0x1d, 0x36, 0x49, 0x49, 0x49, 0x36, // 8
  0x1d, 0x06, 0x49, 0x49, 0x29, 0x1e, // 9
  0x06, 0x00, 0x36, 0x36, 0x00, 0x00, // :
  0x06, 0x00, 0xac, 0x6c, 0x00, 0x00, // ;
  0x0f, 0x08, 0x14, 0x22, 0x41, 0x00, // <
  0x0f, 0x14, 0x14, 0x14, 0x14, 0x14, // =
  0x1e, 0x00, 0x41, 0x22, 0x14, 0x08, // >
  0x1f, 0x02, 0x01, 0x51, 0x09, 0x06, // ?
  
  0x1f, 0x32, 0x49, 0x79, 0x41, 0x3e, // @
  0x1f, 0x7c, 0x12, 0x11, 0x12, 0x7c, // A
  0x17, 0x7f, 0x49, 0x49, 0x49, 0x36, // B
  0x17, 0x3e, 0x41, 0x41, 0x41, 0x22, // C
  0x1f, 0x7f, 0x41, 0x41, 0x22, 0x1c, // D
  0x17, 0x7f, 0x49, 0x49, 0x49, 0x41, // E
  0x17, 0x7f, 0x09, 0x09, 0x09, 0x01, // F
  0x17, 0x3e, 0x41, 0x49, 0x49, 0x7a, // G
  0x17, 0x7f, 0x08, 0x08, 0x08, 0x7f, // H
  0x0e, 0x00, 0x41, 0x7f, 0x41, 0x00, // I
  0x1f, 0x20, 0x40, 0x41, 0x3f, 0x01, // J
  0x1f, 0x7f, 0x08, 0x14, 0x22, 0x41, // K
  0x17, 0x7f, 0x40, 0x40, 0x40, 0x40, // L
  0x1f, 0x7f, 0x02, 0x0c, 0x02, 0x7f, // M
  0x1f, 0x7f, 0x04, 0x08, 0x10, 0x7f, // N
  0x17, 0x3e, 0x41, 0x41, 0x41, 0x3e, // O
  
  0x17, 0x7f, 0x09, 0x09, 0x09, 0x06, // P
  0x17, 0x3e, 0x41, 0x41, 0x41, 0xbe, // Q
  0x1d, 0x7f, 0x09, 0x19, 0x29, 0x46, // R
  0x17, 0x46, 0x49, 0x49, 0x49, 0x31, // S
  0x1f, 0x01, 0x01, 0x7f, 0x01, 0x01, // T
  0x17, 0x3f, 0x40, 0x40, 0x40, 0x3f, // U
  0x1f, 0x1f, 0x20, 0x40, 0x20, 0x1f, // V
  0x1f, 0x3f, 0x40, 0x38, 0x40, 0x3f, // W
  0x1f, 0x63, 0x14, 0x08, 0x14, 0x63, // X
  0x1f, 0x07, 0x08, 0x70, 0x08, 0x07, // Y
  0x1f, 0x61, 0x51, 0x49, 0x45, 0x43, // Z
  0x0e, 0x00, 0x7f, 0x41, 0x41, 0x00, // [
  0x0e, 0x00, 0x03, 0x1c, 0x60, 0x00, // <backslash>
  0x0e, 0x00, 0x41, 0x41, 0x7f, 0x00, // ]
  0x0e, 0x04, 0x02, 0x01, 0x02, 0x04, // ^
  0x1f, 0x40, 0x40, 0x40, 0x40, 0x40, // _

  0x0c, 0x00, 0x00, 0x03, 0x04, 0x00, // `
  0x17, 0x20, 0x54, 0x54, 0x54, 0x78, // a
  0x17, 0x7f, 0x48, 0x44, 0x44, 0x38, // b
  0x17, 0x38, 0x44, 0x44, 0x44, 0x20, // c
  0x1d, 0x38, 0x44, 0x44, 0x48, 0x7f, // d
  0x17, 0x38, 0x54, 0x54, 0x54, 0x18, // e
  0x17, 0x08, 0x7e, 0x09, 0x01, 0x02, // f
  0x17, 0x18, 0xa4, 0xa4, 0xa4, 0x78, // g
  0x17, 0x7f, 0x08, 0x04, 0x04, 0x78, // h
  0x0e, 0x00, 0x44, 0x7d, 0x40, 0x00, // i
  0x0d, 0x40, 0x80, 0x84, 0x7d, 0x00, // j
  0x0f, 0x7f, 0x10, 0x28, 0x44, 0x00, // k
  0x0e, 0x00, 0x41, 0x7f, 0x40, 0x00, // l
  0x1f, 0x7c, 0x04, 0x78, 0x04, 0x78, // m
  0x17, 0x7c, 0x08, 0x04, 0x04, 0x78, // n
  0x17, 0x38, 0x44, 0x44, 0x44, 0x38, // o
  
  0x17, 0xfc, 0x24, 0x24, 0x24, 0x18, // p
  0x17, 0x18, 0x24, 0x24, 0x24, 0xfc, // q
  0x17, 0x7c, 0x08, 0x04, 0x04, 0x08, // r
  0x17, 0x48, 0x54, 0x54, 0x54, 0x20, // s
  0x17, 0x04, 0x3f, 0x44, 0x40, 0x20, // t
  0x1d, 0x3c, 0x40, 0x40, 0x20, 0x7c, // u
  0x1f, 0x1c, 0x20, 0x40, 0x20, 0x1c, // v
  0x1f, 0x3c, 0x40, 0x30, 0x40, 0x3c, // w
  0x1f, 0x44, 0x28, 0x10, 0x28, 0x44, // x
  0x17, 0x1c, 0xa0, 0xa0, 0xa0, 0x7c, // y
  0x1f, 0x44, 0x64, 0x54, 0x4c, 0x44, // z
  0x0e, 0x00, 0x08, 0x36, 0x41, 0x00, // {
  0x04, 0x00, 0x00, 0x7f, 0x00, 0x00, // |
  0x0e, 0x00, 0x41, 0x36, 0x08, 0x00, // }
  0x1f, 0x02, 0x01, 0x02, 0x04, 0x02, // ~
  0x1f, 0xaa, 0x55, 0xaa, 0x55, 0xaa, // <del>
};

uint8_t gfx_x;
uint8_t gfx_y;

uint8_t gfx_get_x()
{
  return gfx_x;
}

uint8_t gfx_get_y()
{
  return gfx_y;
}

void gfx_move(uint8_t x, uint8_t y)
{
  gfx_x = x;
  gfx_y = y;

  display_wait(0);
  display_wait(1);
  display_write(0, 0xb8+y/8);
  display_write(1, 0xb8+y/8);
  
  display_wait(0);
  display_wait(1);
  if (x>64)
  {
    x-=64;
    display_write(0, 0x40);
    display_write(1, 0x40+x);
  }
  else
  {
    display_write(0, 0x40+x);
    display_write(1, 0x40);
  }
}



void gfx_fill(uint8_t val)
{
  for (uint8_t b=0; b<8; ++b)
  {
    display_wait(0);
    display_wait(1);
    display_write(0, 0xb8+b);
    display_write(1, 0xb8+b);
    for (uint8_t i=0; i<64; ++i)
    {
      display_wait(2);
      display_wait(3);
      display_write(2, val);
      display_write(3, val);
    }
  }
  display_wait(0);
  display_wait(1);
  display_write(0, 0xb8);
  display_write(1, 0xb8);
}

void gfx_display_write2(uint8_t data, uint8_t mask)
{
  uint8_t ch=0;
  if (gfx_x>=128)
    return;
  if (gfx_x>=64)
    ch++;

  display_wait(ch);
  display_read(ch+2); // dummy read
  
  uint8_t tp = display_read(ch+2);
  uint8_t val = (data & mask) | (tp & ~mask);
  
  display_wait(ch);
  display_write(ch, 0x40|gfx_x);
  
  display_wait(ch);
  display_write(ch+2, val);
  gfx_x++;
}



uint8_t gfx_char_width(char ch, uint8_t prop)
{
  uint8_t res = 0;
  uint8_t c = (uint8_t) ch;
  if ((c<0x20) || (c>=0x80))
    c=0x80;
  c-=0x20;

  const uint8_t * ftp = fontTiles;
  ftp += (6 * (int)c);
  
  uint8_t mask = *ftp++;
  if (prop==0)
    mask=0x1f;
  
  for (uint8_t i=0; i<5; ++i)
  {
    if (mask&0x01)
      res++;
    mask>>=1;
    ftp++;
  }
  return res;
}


void gfx_print_char_base(char ch, uint8_t prop, int8_t shval)
{
  uint8_t c = (uint8_t) ch;
  if ((c<0x20) || (c>=0x80))
    c=0x80;
  c-=0x20;

  const uint8_t * ftp = fontTiles;
  ftp += (6 * (int)c);
  
  uint8_t mask = *ftp++;
  if (prop==0)
    mask=0x1f;
  
  for (uint8_t i=0; i<5; ++i)
  {
    if (mask&0x01)
    {
      if (shval>=0)
      {
        uint8_t tv = (uint8_t)*ftp << shval;
        uint8_t tm = (uint8_t)0xff << shval;
        gfx_display_write2(tv, tm);
      } else {
        uint8_t tv = ((uint8_t)*ftp >> -shval);
        uint8_t tm = ((uint8_t)0xff >> -shval);
        gfx_display_write2(tv, tm);
      }
    }
    mask>>=1;
    ftp++;
  }
  if (shval>=0)
  {
    uint8_t tm = (uint8_t)0xff << shval;
    gfx_display_write2(0x00, tm);
  } else {
    uint8_t tm = ((uint8_t)0xff >> -shval);
    gfx_display_write2(0x00, tm);
  }
}

void gfx_print_char(char ch, uint8_t prop)
{
  uint8_t x = gfx_x;
  int8_t shval = gfx_y%8;
  gfx_print_char_base(ch, prop, shval);
  if (shval)
  {
    gfx_move(x, gfx_y+8);
    gfx_print_char_base(ch, prop, shval-8);
    gfx_move(gfx_x, gfx_y-8);
  }
}


void gfx_print_text(char *txt, uint8_t prop)
{
  while(*txt)
    gfx_print_char(*txt++, prop);
}

uint8_t gfx_text_width(char *txt, uint8_t prop)
{
  uint8_t res=0;
  while(*txt)
    res += gfx_char_width(*txt++, prop) + 1;
  return res;
}

